package game

import (
	"errors"
	"time"
)

type LanguageStore struct {
	langs []string
	List  map[string][]LanguageItem
}

func NewLanguageStore() *LanguageStore {
	ls := &LanguageStore{
		langs: []string{},
		List:  map[string][]LanguageItem{},
	}
	return ls
}

func (store *LanguageStore) Parse(provider *DataProvider, item *DataInlineExtend) {
	item.fill(store, provider.Name+":")
}

func (store *LanguageStore) AddLang(lang string) {
	store.langs = append(store.langs, lang)
	store.List[lang] = []LanguageItem{}
}

func (store *LanguageStore) Append(key string, content map[string]string) {
	for _, lang := range store.langs {
		store.List[lang] = append(store.List[lang], LanguageItem{
			Key:   key,
			Value: content[lang],
		})
	}
}

type ModuleProvider struct {
	Name    string
	Depends []string

	OnInit      EnvHandle
	OnReload    EnvHandle
	OnNamespace EnvHandle
	OnApp       AppHandle
}

type DataProvider struct {
	Array    bool
	Language bool
	Manager  bool
	Name     string
	Get      func() (interface{}, error)
}

func (provider *DataProvider) LanguageKey(extend *DataInlineExtend, field string) string {
	return provider.Name + ":" + extend.getLanguageKey() + "/" + field
}

func (provider *DataProvider) LanguagePrefix(languageKey string) string {
	return provider.Name + ":" + languageKey
}

type DataProvide interface {
	Inline() *DataInlineExtend
	GetKey() string
}

type DataProvideSlice []DataProvide

type DataInlineExtend struct {
	key       string
	languages map[string]map[string]string
	children  map[string][]*DataInlineExtend
	parent    *DataInlineExtend
}

func NewDataInlineExtend(key string) *DataInlineExtend {
	extend := &DataInlineExtend{
		key:       key,
		languages: map[string]map[string]string{},
	}
	return extend
}

func (extend *DataInlineExtend) fill(store *LanguageStore, prefix string) {
	prefix = prefix + extend.key
	for field, info := range extend.languages {
		if field != "" {
			field = "/" + field
		}
		store.Append(prefix+field, info)
	}
	for relation, children := range extend.children {
		for _, child := range children {
			child.fill(store, prefix+"/"+relation+"/")
		}
	}
}

func (extend *DataInlineExtend) getLanguageKey() string {
	prefix := ""
	if extend.parent != nil {
		prefix = extend.parent.getLanguageKey() + "/"
	}
	return prefix + extend.GetKey()
}

func (extend *DataInlineExtend) GetKey() string {
	return extend.key
}

func (extend *DataInlineExtend) Languages() map[string]map[string]string {
	return extend.languages
}

func (extend *DataInlineExtend) AddMulti(other *DataInlineExtend) *DataInlineExtend {
	for field, language := range other.languages {
		extend.languages[field] = language
	}
	return extend
}

func (extend *DataInlineExtend) Add(field string, language map[string]string) *DataInlineExtend {
	extend.languages[field] = language
	return extend
}

func (extend *DataInlineExtend) Bind(language map[string]string) *DataInlineExtend {
	extend.languages[""] = language
	return extend
}
func (extend *DataInlineExtend) Attach(relation string, inline *DataInlineExtend) *DataInlineExtend {
	if extend.children == nil {
		extend.children = map[string][]*DataInlineExtend{}
	}
	value, ok := extend.children[relation]
	if !ok {
		value = []*DataInlineExtend{}
	}
	extend.children[relation] = append(value, inline)
	inline.parent = extend
	return extend
}

func (extend *DataInlineExtend) Get(lang string, field string) string {
	return extend.languages[lang][field]
}

type DataExtend struct {
	DataInlineExtend
	updateTime *time.Time
	children   []*DataInlineExtend
}

func NewDataExtend(key string, updateTime *time.Time) *DataExtend {
	extend := &DataExtend{
		DataInlineExtend: DataInlineExtend{
			key:       key,
			languages: map[string]map[string]string{},
		},
		updateTime: updateTime,
		children:   []*DataInlineExtend{},
	}
	return extend
}

func (extend *DataExtend) HasUpdate(updateTime *time.Time) bool {
	return extend.updateTime.After(*updateTime)
}

func (extend *DataExtend) AddMulti(other *DataExtend) *DataExtend {
	extend.DataInlineExtend.AddMulti(&other.DataInlineExtend)
	return extend
}
func (extend *DataExtend) Add(field string, language map[string]string) *DataExtend {
	extend.DataInlineExtend.Add(field, language)
	return extend
}

func (extend *DataExtend) GetExtend() *DataExtend {
	return extend
}

func (extend *DataExtend) Inline() *DataInlineExtend {
	return &extend.DataInlineExtend
}

func (extend *DataExtend) Bind(language map[string]string) *DataExtend {
	extend.DataInlineExtend.Bind(language)
	return extend
}

var (
	providers = make(map[string]ModuleProvider)
)

func RegisterGlobalModule(module ModuleProvider) error {
	if _, ok := providers[module.Name]; ok {
		return errors.New("[ Game ] Module " + module.Name + " is exist!")
	}
	providers[module.Name] = module
	return nil
}
